package parser;

import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import lexer.Lexer;
import symbols.*;
import tools.SyntaxTree;

public class Parser {
    public static void main(String[] args) throws IOException {
        // 词法分析
        Lexer lexer = new Lexer("pTest7.i");
        lexer.readCode();
        List<Token> tokens = lexer.scan();
        // 语法分析
        Parser parser = new Parser();
        parser.setTokens(tokens);
        parser.run();
        String r = parser.getSyntaxTree().toString();
        System.out.println("下面输出语法树:\n" + r);
        try (FileWriter fw = new FileWriter("pTest7.txt")) {
            fw.write(r);
            fw.flush();
        }
        System.out.println("下面输出四元式序列:");
        int line = 0;
        for (Quaternion q : parser.getQList()) {
            System.out.println(line++ + ": " + q);
        }
    }

    private SyntaxTree syntaxTree = new SyntaxTree();
    private List<Token> tokens;
    private Token t;
    private int index = 1;
    private List<Quaternion> qList = new ArrayList<>();// 四元式列表

    public void setTokens(List<Token> tokens) {
        this.tokens = tokens;
    }

    public void run() {
        if (tokens.size() == 0)
            throw new Error("传入Token为空!");
        t = tokens.get(0);
        prog(new AttInfo(0));
        backfill();
    }

    public SyntaxTree getSyntaxTree() {
        return syntaxTree;
    }

    public List<Quaternion> getQList() {
        return qList;
    }

    // <Prog> → <Type> main() <Block>
    private SynInfo prog(AttInfo info) {
        SynInfo rInfo = new SynInfo();
        syntaxTree.put(new Word("Prog", 529), info.depth++);
        type(info.clone());
        if (t.equals(new Word("main", Tag.ID))) {
            match(info.clone());
            if (t.tag == '(') {
                match(info.clone());
                if (t.tag == ')') {
                    match(info.clone());
                    block(info.clone());
                    qList.add(new Quaternion("end", null, null, "_"));
                } else {
                    throw new Error("在'" + t + "'前, 缺少')'!");
                }
            } else {
                throw new Error("在'" + t + "'前, 缺少'('!");
            }
        } else {
            throw new Error("在'" + t + "'前, 缺少main!");
        }
        return rInfo;
    }

    // <Block> → { <Decls> <STMTS> }
    private SynInfo block(AttInfo info) {
        SynInfo rInfo = new SynInfo();
        if (t.tag == '{') {
            syntaxTree.put(new Word("Block", 519), info.depth++);
            match(info.clone());
            decls(info.clone());
            stmts(info.clone());
            if (t.tag == '}') {
                match(info.clone());
            } else {
                throw new Error("在'" + t + "'前, 缺少'}'!");
            }
        } else {
            throw new Error("在'" + t + "'前, 缺少'{'!");
        }
        return rInfo;
    }

    // 定义相关
    // <Decls> → <Type> <NameList> ; <Decls> | empty
    private SynInfo decls(AttInfo info) {
        SynInfo rInfo = new SynInfo();
        if (t.tag == Tag.TYPE) {
            syntaxTree.put(new Word("Decls", 520), info.depth++);
            String type = type(info.clone()).type;
            info.type = type;
            nameList(info.clone());
            if (t.tag == ';') {
                match(info.clone());
                decls(info.clone());
            } else {
                throw new Error("在'" + t + "'前, 缺少';'!");
            }
        } else {
            // do nothing
        }
        return rInfo;
    }

    // <NameList> → <Name> <NameList1>
    private SynInfo nameList(AttInfo info) {
        String type = info.type;
        SynInfo rInfo = new SynInfo();
        if (t.tag == Tag.ID) {
            syntaxTree.put(new Word("NameList", 521), info.depth++);
            defID();
            name(info.clone());
            qList.add(new Quaternion(type, null, null, "$" + (idIndex - 1)));
            nameList1(info.clone());
        } else {
            throw new Error("在'" + t + "'前, 缺少ID!");
        }
        return rInfo;
    }

    // <NameList1> → , <Name> <NameList1> | empty
    private SynInfo nameList1(AttInfo info) {
        String type = info.type;
        SynInfo rInfo = new SynInfo();
        if (t.tag == ',') {
            syntaxTree.put(new Word("NameLis1", 521), info.depth++);
            match(info.clone());
            defID();
            name(info.clone());
            qList.add(new Quaternion(type, null, null, "$" + (idIndex - 1)));
            nameList1(info.clone());
        } else {
            // do nothing
        }
        return rInfo;
    }

    // <Type> → int
    private SynInfo type(AttInfo info) {
        SynInfo rInfo = new SynInfo();
        if (t.tag == Tag.TYPE) {
            syntaxTree.put(new Word("Type", 522), info.depth++);
            if (t.equals(Type._int)) {
                match(info.clone());
                rInfo.type = "int";
            } else {
                throw new Error("在'" + t + "'前, 不支持的变量类型!");
            }
        } else {
            throw new Error("在'" + t + "'前, 缺少Type!");
        }
        return rInfo;
    }

    // <Name> → id
    private SynInfo name(AttInfo info) {
        SynInfo rInfo = new SynInfo();
        if (t.tag == Tag.ID) {
            syntaxTree.put(new Word("Name", 523), info.depth++);
            match(info.clone());
        } else {
            throw new Error("在'" + t + "'前, 缺少Name!");
        }
        return rInfo;
    }

    // 赋值相关
    // <STMTS> → <STMT> <STMTS> | empty
    private SynInfo stmts(AttInfo info) {
        SynInfo rInfo = new SynInfo();
        if (t.tag == Tag.ID || t.tag == Tag.IF || t.tag == Tag.WHILE) {
            syntaxTree.put(new Word("STMTS", 524), info.depth++);
            stmt(info.clone());
            stmts(info.clone());
        } else {
            // do nothing
        }
        return rInfo;
    }

    private HashMap<String, Integer> idMap = new HashMap<>();
    private int idIndex = 1;
    private int sIndex = 1;

    /*
     * <STMT> → <Name> = <Expr> ;
     * <STMT> → if ( <BOOL> ) <STMT> <STMT1>
     * <STMT> → while ( <BOOL> ) <STMT>
     */
    private SynInfo stmt(AttInfo info) {
        SynInfo rInfo = new SynInfo();
        if (t.tag == Tag.ID) {
            rInfo = pID(info);
        } else if (t.tag == Tag.IF) {
            pIF(info);
        } else if (t.tag == Tag.WHILE) {
            pWHILE(info);
        } else {
            throw new Error("在'" + t + "'前, STMT错误!");
        }
        return rInfo;
    }

    private void pWHILE(AttInfo info) throws Error {
        syntaxTree.put(new Word("STMT", 525), info.depth++);
        match(info.clone());
        if (t.tag == '(') {
            match(info.clone());
            int s1 = sIndex++;
            int s2 = sIndex++;
            qList.add(new Quaternion("#", null, null, "S" + s1));
            int boolID = bool(info.clone()).id;
            if (t.tag == ')') {
                match(info.clone());
                qList.add(new Quaternion("jz", "$" + boolID, null, "S" + s2));
                stmt(info.clone());
                qList.add(new Quaternion("j", null, null, "S" + s1));
                qList.add(new Quaternion("#", null, null, "S" + s2));
            } else {
                throw new Error("在'" + t + "'前, 缺少')'!");
            }
        } else {
            throw new Error("在'" + t + "'前, 缺少'('!");
        }
    }

    private void pIF(AttInfo info) throws Error {
        syntaxTree.put(new Word("STMT", 525), info.depth++);
        match(info.clone());
        if (t.tag == '(') {
            match(info.clone());
            SynInfo boolInfo = bool(info.clone());
            int jIndex = qList.size();
            if (t.tag == ')') {
                match(info.clone());
                stmt(info.clone());
                info.sIndex = sIndex;
                qList.add(jIndex, new Quaternion("jz", "$" + boolInfo.id, null, "S" + sIndex++));
                stmt1(info.clone());
            } else {
                throw new Error("在'" + t + "'前, 缺少')'!");
            }
        } else {
            throw new Error("在'" + t + "'前, 缺少'('!");
        }
    }

    private SynInfo pID(AttInfo info) throws Error {
        SynInfo rInfo = new SynInfo();
        String op;
        String arg1;
        String arg2;
        String result;
        rInfo.id = useID();
        syntaxTree.put(new Word("STMT", 525), info.depth++);
        name(info.clone());
        if (t.tag == '=') {
            match(info.clone());
            op = "=";
            SynInfo s = expr(info.clone());
            arg1 = (s.id > 0) ? "$" + s.id : "" + s.value;
            arg2 = null;
            result = "$" + rInfo.id;
            if (t.tag == ';') {
                match(info.clone());
                qList.add(new Quaternion(op, arg1, arg2, result));
            } else {
                throw new Error("在'" + t + "'前, 缺少';'!");
            }
        } else {
            throw new Error("在'" + t + "'前, 缺少'='!");
        }
        return rInfo;
    }

    // <STMT1> → else <STMT> | empty
    private SynInfo stmt1(AttInfo info) {
        SynInfo rInfo = new SynInfo();
        if (t.tag == Tag.ELSE) {
            syntaxTree.put(new Word("STMT1", 526), info.depth++);
            match(info.clone());
            int s = sIndex;
            qList.add(new Quaternion("j", null, null, "S" + sIndex++));
            qList.add(new Quaternion("#", null, null, "S" + info.sIndex));
            stmt(info.clone());
            qList.add(new Quaternion("#", null, null, "S" + s));
        } else {
            // do nothing
        }
        return rInfo;
    }

    // 逻辑运算相关文法
    // <BOOL> → <Expr> <RelOp> <Expr>
    private SynInfo bool(AttInfo info) {
        SynInfo rInfo = new SynInfo();
        syntaxTree.put(new Word("Bool", 527), info.depth++);
        SynInfo gInfo = expr(info.clone());
        String arg1 = (gInfo.id > 0) ? "$" + gInfo.id : "" + gInfo.value;
        String op = t.toString();// 记录逻辑运算符
        relOp(info.clone());
        gInfo = expr(info.clone());
        String arg2 = (gInfo.id > 0) ? "$" + gInfo.id : "" + gInfo.value;

        int tempID = defTempID();
        qList.add(new Quaternion("bool", null, null, "$" + tempID));
        qList.add(new Quaternion(op, arg1, arg2, "$" + tempID));

        rInfo.id = tempID;
        return rInfo;
    }

    // <RelOp> → < | <= | > | >= | == | !=
    private SynInfo relOp(AttInfo info) {
        SynInfo rInfo = new SynInfo();
        switch (t.tag) {
            case '<':
            case Tag.LE:
            case '>':
            case Tag.GE:
            case Tag.EQ:
            case Tag.NE:
                syntaxTree.put(new Word("RelOp", 528), info.depth++);
                match(info.clone());
                break;
            default:
                throw new Error("在'" + t + "'前, RelOp错误!");
        }
        return rInfo;
    }

    // 表达式相关
    // <Expr> → <Term> <Expr1>
    private SynInfo expr(AttInfo info) {
        syntaxTree.put(new Word("Expr", 512), info.depth++);
        SynInfo gInfo = term(info.clone());
        info.value = gInfo.value;
        info.id = gInfo.id;
        SynInfo eInfo = expr1(info.clone());
        return (eInfo.id == -2) ? gInfo : eInfo;
    }

    // <Expr1> → <AddOp> <Term> <Expr1> | empty
    private SynInfo expr1(AttInfo info) {
        SynInfo rInfo = new SynInfo();
        if (t.tag == '+' || t.tag == '-') {
            String op = t.toString();
            String arg1 = (info.id > 0) ? "$" + info.id : "" + info.value;
            syntaxTree.put(new Word("Expr1", 513), info.depth++);

            addOp(info.clone());

            SynInfo gInfo = term(info.clone());
            int tempID = defTempID();
            qList.add(new Quaternion("int", null, null, "$" + tempID));
            String arg2 = (gInfo.id > 0) ? "$" + gInfo.id : "" + gInfo.value;
            qList.add(new Quaternion(op, arg1, arg2, "$" + tempID));

            info.id = tempID;// 设定继承属性
            SynInfo s = expr1(info.clone());// 获取综合属性
            rInfo.id = (s.id > 0) ? s.id : tempID;
        } else {
            rInfo.value = info.value;
            rInfo.id = -2;
        }
        return rInfo;
    }

    // <Term> → <Factor> <Term1>
    private SynInfo term(AttInfo info) {
        syntaxTree.put(new Word("Term", 514), info.depth++);
        SynInfo rInfo = factor(info.clone());// 继承
        info.id = rInfo.id;
        info.value = rInfo.value;
        SynInfo gInfo = term1(info.clone());
        if (gInfo.id > 0) {
            rInfo.id = gInfo.id;// 综合
        } else {
            rInfo.value = gInfo.value;
        }
        return rInfo;
    }

    // <Term1> → <MulOp> <Factor> <Term1> | empty
    private SynInfo term1(AttInfo info) {
        SynInfo rInfo = new SynInfo();
        if (t.tag == '*' || t.tag == '/') {
            String op = t.toString();
            String arg1 = (info.id > 0) ? "$" + info.id : "" + info.value;
            syntaxTree.put(new Word("Term1", 515), info.depth++);

            mulOp(info.clone());

            SynInfo gInfo = factor(info.clone());
            int tempID = defTempID();
            qList.add(new Quaternion("int", null, null, "$" + tempID));
            String arg2 = (gInfo.id > 0) ? "$" + gInfo.id : "" + gInfo.value;
            qList.add(new Quaternion(op, arg1, arg2, "$" + tempID));

            info.id = tempID;// 继承属性
            SynInfo s = term1(info.clone());// 获取综合属性
            rInfo.id = (s.id > 0) ? s.id : tempID;
        } else {
            rInfo.value = info.value;
            rInfo.id = -2;
        }
        return rInfo;
    }

    // <Factor> → id | number | ( <Expr> )
    private SynInfo factor(AttInfo info) {
        SynInfo rInfo = new SynInfo();
        if (t.tag == Tag.ID) {
            syntaxTree.put(new Word("Factor", 516), info.depth++);
            rInfo.id = useID();
            match(info.clone());
        } else if (t.tag == Tag.NUM) {
            syntaxTree.put(new Word("Factor", 516), info.depth++);
            Num n = (Num) t;
            rInfo.value = n.value;
            match(info.clone());
        } else if (t.tag == '(') {
            syntaxTree.put(new Word("Factor", 516), info.depth++);
            match(info.clone());
            rInfo.id = expr(info.clone()).id;
            if (t.tag == ')') {
                match(info.clone());
            } else {
                throw new Error("在'" + t + "'前, 未匹配到右括号!");
            }
        } else {
            throw new Error("在'" + t + "'前, 表达式错误!");
        }
        return rInfo;
    }

    // <AddOp> → + | -
    private SynInfo addOp(AttInfo info) {
        SynInfo rInfo = new SynInfo();
        if (t.tag == '+' || t.tag == '-') {
            syntaxTree.put(new Word("AddOp", 517), info.depth++);
            match(info.clone());
        } else {
            throw new Error("在'" + t + "'前, 未匹配到addOp!");
        }
        return rInfo;
    }

    // <MulOp> → * | /
    private SynInfo mulOp(AttInfo info) {
        SynInfo rInfo = new SynInfo();
        if (t.tag == '*' || t.tag == '/') {
            syntaxTree.put(new Word("MulOp", 518), info.depth++);
            match(info.clone());
        } else {
            throw new Error("在'" + t + "'前, 未匹配到mulOp!");
        }
        return rInfo;
    }

    private SynInfo match(AttInfo info) {
        SynInfo rInfo = new SynInfo();
        syntaxTree.put(t, info.depth);
        t = (index < tokens.size()) ? tokens.get(index) : new Token(-1);
        index++;
        return rInfo;
    }

    private void defID() throws Error {
        if (idMap.containsKey(t.toString())) {
            throw new Error("在'" + t + "'前, 重复定义!");
        }
        idMap.put(t.toString(), idIndex);
        idIndex++;
    }

    private int useID() {
        if (!idMap.containsKey(t.toString())) {
            throw new Error("在'" + t + "'前, 未定义的使用!");
        }
        return idMap.get(t.toString());
    }

    private int tempCount = 0;

    private int defTempID() {
        idMap.put("_temp_" + tempCount++, idIndex);
        return idIndex++;
    }

    /** 将标志Sx所在位置回填 */
    private void backfill() {
        for (int i = 0; i < qList.size(); i++) {
            Quaternion q = qList.get(i);
            String s = q.result;
            if (q.op.equals("#")) {
                for (Quaternion q2 : qList) {
                    if (q2.result.equals(s)) {
                        q2.result = "" + i;
                    }
                }
                qList.remove(i--);// 删除后索引同步调整
            }
        }
    }
}
